package com.company.pdd;

import java.util.Arrays;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class QueueMain {
    public static void main(String[] args) {
        MyQueue myQueue = new MyQueue(9);
        new Thread(()->{
            try {
                myQueue.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t1").start();
        new Thread(()->{
            try {
                myQueue.put(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t2").start();
        new Thread(()->{
            try {
                myQueue.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t3").start();
        new Thread(()->{
            try {
                myQueue.put(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t4").start();
        new Thread(()->{
            try {
                myQueue.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t5").start();
        new Thread(()->{
            try {
                myQueue.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t6").start();
        new Thread(()->{
            try {
                myQueue.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t7").start();
        new Thread(()->{
            try {
                myQueue.put(90);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t8").start();



    }
}

class MyQueue{

    int front;
    int rear;
    int size;
    int[] queue;


    Lock lock = new ReentrantLock();
    Condition empty = lock.newCondition();
    Condition full = lock.newCondition();

    public MyQueue(int size){
        this.size = size;
        queue = new int[size];
        front = 0;
        rear = 0;
    }

    private int size(){
        return rear - front;
    }

    private boolean isFull(){
        return rear == size - 1;
    }

    private boolean isEmpty(){
        return rear == front;
    }

    public void put(int value) throws InterruptedException {
        lock.lock();
        try {
            while (isFull()){
                empty.await();
            }
            queue[rear] = value;
            System.out.println("-------------------");
            System.out.println(Thread.currentThread().getName());
            System.out.println(Arrays.toString(queue));
            System.out.println("-------------------");
            if(isFull()){
                rear = 0;
            }else{
                rear++;
            }
            System.out.println(Arrays.toString(queue));
            full.signalAll();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public int take() throws InterruptedException{
        int res = 0;
        lock.lock();
        try {
            while (isEmpty()){
                full.await();
            }
            res = queue[front];
            queue[front] = 0;
            System.out.println("*******************");
            System.out.println(Thread.currentThread().getName());
            System.out.println(Arrays.toString(queue));
            System.out.println("********************");
            if(isEmpty()){
                front = 0;
            }else{
                front++;
            }
            System.out.println(Arrays.toString(queue));
            empty.signalAll();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return 0;
    }

}
